package org.ims.inv.service.project.impl;

import java.util.List;

import org.hibernate.Hibernate;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.ims.inv.dao.project.DAOProject;
import org.ims.inv.model.project.ModelProject;
import org.ims.inv.model.project.ModelProjectProcess;
import org.ims.inv.model.system.ModelAppUser;
import org.ims.inv.service.project.ServiceProject;
import org.ims.inv.vo.VoProjectCond;
import org.ims.inv.web.util.ContextUtil;

import cn.trymore.core.exception.DAOException;
import cn.trymore.core.exception.ServiceException;
import cn.trymore.core.service.impl.ServiceGenericImpl;
import cn.trymore.core.util.UtilString;
import cn.trymore.core.web.paging.PaginationSupport;
import cn.trymore.core.web.paging.PagingBean;

/**
 * Service: 项目
 * 
 * @author Jeccy.Zhao
 *
 */
public class ServiceProjectImpl
extends ServiceGenericImpl<ModelProject> implements ServiceProject
{

	/**
	 * 跟进
	 */
	private static final String ARCHIVE_STATUS_FOLLOW = "follow";
	
	/**
	 * 立项
	 */
	private static final String ARCHIVE_STATUS_APPROVED = "approved";
	
	/**
	 * 储备
	 */
	private static final String ARCHIVE_STATUS_ARCHIVED = "archived";
	
	/**
	 * 否决
	 */
	private static final String ARCHIVE_STATUS_REJECTED = "rejected";
	
	/**
	 * Repository of project
	 */
	private DAOProject daoProject;
	
	
	public ServiceProjectImpl(DAOProject dao)
	{
		super(dao);
		
		this.daoProject = dao;
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.project.ServiceProject#getProjectsByCriterion(org.ims.inv.model.project.ModelProject)
	 */
	@Override
	public List<ModelProject> getProjectsByCriterion(ModelProject entity)
			throws ServiceException
	{
		try
		{
			return this.daoProject.getListByCriteria(this.getCriterias(entity));
		} 
		catch (DAOException e)
		{
			throw new ServiceException(e);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.project.ServiceProject#getUnAppropriatedProjects()
	 */
	@Override
	public PaginationSupport<ModelProject> getUnAppropriatedProjects (
			ModelProject entity, PagingBean pagingBean) throws ServiceException
	{
		try
		{
			
			DetachedCriteria criteria = this.getCriterias(entity);
			
			if (entity.getProjectStatus() != null)
			{
				criteria.add(Restrictions.isNull("currentProcess"));
			}
			else
			{
				criteria.add(Restrictions.sqlRestriction("p_currentProcess IS NOT NULL"));
			}
			
			
			return this.daoProject.findPageByCriteria(criteria, pagingBean);
		}
		catch (DAOException e)
		{
			throw new ServiceException(e);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.project.ServiceProject#getFirstTrialProjects(org.ims.inv.model.project.ModelProject, cn.trymore.core.web.paging.PagingBean)
	 */
	@Override
	public PaginationSupport<ModelProject> getFirstTrialProjects(
			ModelProject entity, PagingBean pagingBean) throws ServiceException
	{
		try
		{
			entity.setProjectStatus(ModelProject.EProjectStatus.APPROVING.getValue());
			
			DetachedCriteria criteria = this.getCriterias(entity);
			criteria.createCriteria("currentProcess").add(Restrictions.eq("sequence", 1));
			
			return this.daoProject.findPageByCriteria(criteria, pagingBean);
		}
		catch (DAOException e)
		{
			throw new ServiceException(e);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.project.ServiceProject#getRetrialProjects(org.ims.inv.model.project.ModelProject, cn.trymore.core.web.paging.PagingBean)
	 */
	@Override
	public PaginationSupport<ModelProject> getRetrialProjects(
			ModelProject entity, PagingBean pagingBean) throws ServiceException
	{
		try
		{
			entity.setProjectStatus(ModelProject.EProjectStatus.APPROVING.getValue());
			
			DetachedCriteria criteria = this.getCriterias(entity);
			criteria.createCriteria("currentProcess").add(Restrictions.eq("sequence", 2));
			
			return this.daoProject.findPageByCriteria(criteria, pagingBean);
		}
		catch (DAOException e)
		{
			throw new ServiceException(e);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.project.ServiceProject#getProjectsByStatus(org.ims.inv.model.project.ModelProject, java.lang.String, cn.trymore.core.web.paging.PagingBean)
	 */
	@Override
	public PaginationSupport<ModelProject> getProjectsByArchiveStatus (
			ModelProject entity, String status, Integer visible, PagingBean pagingBean) throws ServiceException
	{
		try
		{
			VoProjectCond condVO = entity.getCondVO();
			DetachedCriteria criteria = this.getCriterias(entity);
			
			if (ARCHIVE_STATUS_FOLLOW.equalsIgnoreCase(status))
			{
				// 跟进项目
				if (condVO == null || !condVO.isValid())
				{
					criteria.add(Restrictions.or(
						Restrictions.isNotNull("currentProcess"), 
						Restrictions.in("projectStatus", 
							new Object[] { 
								ModelProject.EProjectStatus.APPROVING.getValue(),  
								ModelProject.EProjectStatus.TOPOST.getValue(),
								ModelProject.EProjectStatus.RETURNED.getValue()
							} 
						)
					));
				}
				
				criteria.add(Restrictions.ne("projectStatus", 
						ModelProject.EProjectStatus.SUSPENDED.getValue()));
			}
			else if (ARCHIVE_STATUS_APPROVED.equalsIgnoreCase(status))
			{
				// 立项项目
				criteria.add(Restrictions.isNull("currentProcess"));
				criteria.add(Restrictions.eq("projectStatus", 
						ModelProject.EProjectStatus.APPROVED.getValue()));
			}
			else if (ARCHIVE_STATUS_ARCHIVED.equalsIgnoreCase(status))
			{
				// 储备项目
				criteria.add(Restrictions.isNull("currentProcess"));
				criteria.add(Restrictions.eq("archived", 
						ModelProject.EProjectArchived.ARCHIEVED.getValue()));
				criteria.add(Restrictions.eq("projectStatus", 
						ModelProject.EProjectStatus.SUSPENDED.getValue()));
			}
			else if (ARCHIVE_STATUS_REJECTED.equalsIgnoreCase(status))
			{
				// 否决项目
				criteria.add(Restrictions.isNull("currentProcess"));
				criteria.add(Restrictions.eq("projectStatus", 
						ModelProject.EProjectStatus.REJECTED.getValue()));
			}
			else
			{
				// throw new ServiceException("未知的项目请求状态...");
			}
			
			if (visible == null)
			{
				// 我的项目库
				String userId = ContextUtil.getCurrentUser().getId();

				if (condVO != null && UtilString.isNotEmpty(condVO.getCondParticipantType()))
				{
					if (condVO.getCondParticipantType().equals("1"))
					{
						// 负责项目
						criteria.add(Restrictions.sqlRestriction(
								"p_manager = ?", Integer.valueOf(userId), Hibernate.INTEGER));
					}
					else if (condVO.getCondParticipantType().equals("0"))
					{
						// 参与项目
						criteria.add(Restrictions.sqlRestriction(
								"FIND_IN_SET(?, `p_attendee_ids`) > 0", userId, Hibernate.STRING));
						
						criteria.add(Restrictions.sqlRestriction(
								"(p_manager IS NULL or p_manager != ?)", Integer.valueOf(userId), Hibernate.INTEGER));
					}
				}
				else
				{
					criteria.add(Restrictions.or(
						Restrictions.sqlRestriction("p_manager = ?", Integer.valueOf(userId), Hibernate.INTEGER), 
						Restrictions.sqlRestriction("FIND_IN_SET(?, `p_attendee_ids`) > 0", userId, Hibernate.STRING)));
				}
			}
			else
			{
				// 公司项目库
				if (visible.equals(ModelProject.EProjectVisible.PUBLIC.getValue()))
				{
					// 公司内部公开
					criteria.add(Restrictions.eq("projectVisibleRange", visible));
				}
				else if (visible.equals(ModelProject.EProjectVisible.LEADERSHIP.getValue()))
				{
					// 不进行条件筛选, 默认能看到所有项目
				}
			}
			
			return this.daoProject.findPageByCriteria(criteria, pagingBean);
		}
		catch (DAOException e)
		{
			throw new ServiceException(e);
		}
	}
	/*
	 * (non-Javadoc)
	 * @see cn.trymore.core.service.impl.ServiceGenericImpl#getCriterias(cn.trymore.core.model.ModelBase)
	 */
	@Override
	protected DetachedCriteria getCriterias(ModelProject domain)
	{
		DetachedCriteria criteria = DetachedCriteria.forClass(ModelProject.class);
		
		if (domain != null)
		{
			if (domain.getProjectManager() != null)
			{
				
				ModelAppUser projectManager = domain.getProjectManager();
				
				if (domain.isRelevantPersonIncluded() && UtilString.isNotEmpty(projectManager.getId()))
				{
					// 过滤项目参与人员
					criteria.add(Restrictions.sqlRestriction("(p_manager = " + projectManager.getId() + 
							" or FIND_IN_SET(" + projectManager.getId() + ", `p_attendee_ids`) > 0)"));
				}
				else
				{
					if (UtilString.isNotEmpty(projectManager.getUsername()))
					{
						criteria.createCriteria("projectManager").add(
								Restrictions.like("username", projectManager.getUsername(), MatchMode.ANYWHERE));
					}
					else if (UtilString.isNotEmpty(projectManager.getId()))
					{
						criteria.createCriteria("projectManager").add(
								Restrictions.eq("id", projectManager.getId()));
					}
				}
			}
			
			if (domain.getProjectRecorder() != null)
			{
				ModelAppUser projectRecorder = domain.getProjectRecorder();
				
				if (UtilString.isNotEmpty(projectRecorder.getUsername()))
				{
					criteria.createCriteria("projectRecorder").add(
							Restrictions.like("username", projectRecorder.getUsername(), MatchMode.ANYWHERE));
				}
				else if (UtilString.isNotEmpty(projectRecorder.getId()))
				{
					criteria.createCriteria("projectRecorder").add(
							Restrictions.eq("id", projectRecorder.getId()));
				}
			}
			
			if (UtilString.isNotEmpty(domain.getProjectNo()))
			{
				criteria.add(Restrictions.like("projectNo", domain.getProjectNo(), MatchMode.ANYWHERE));
			}
			
			if (domain.getProjectType() != null)
			{
				criteria.createCriteria("projectType").add(Restrictions.eq("id", domain.getProjectType().getId()));
			}
			
			if (UtilString.isNotEmpty(domain.getProjectInventor()))
			{
				criteria.add(Restrictions.eq("projectInventor", domain.getProjectInventor()));
			}
			
			if (UtilString.isNotEmpty(domain.getProjectName()))
			{
				criteria.add(Restrictions.like("projectName", domain.getProjectName(), MatchMode.ANYWHERE));
			}
			
			if (domain.getProjectStatus() != null)
			{
				criteria.add(Restrictions.eq("projectStatus", domain.getProjectStatus()));
			}
			
			if (domain.getCurrentProcess() != null)
			{
				DetachedCriteria subCriteria = criteria.createCriteria("currentProcess");
				
				if (UtilString.isNotEmpty(domain.getCurrentProcess().getNodeTitle()))
				{
					subCriteria.add(
							Restrictions.eq("nodeTitle", domain.getCurrentProcess().getNodeTitle()));
				}
				
				if (domain.getCurrentProcess().getMaterialStatus() != null)
				{
					subCriteria.add(
							Restrictions.eq("materialStatus", domain.getCurrentProcess().getMaterialStatus()));
				}
				
				if (UtilString.isNotEmpty(domain.getCurrentProcess().getNodeKey()))
				{
					subCriteria.add(
							Restrictions.eq("nodeKey", domain.getCurrentProcess().getNodeKey()));
				}
				
				subCriteria.add(Restrictions.sqlRestriction(
					"(depend_flow IS NULL or depend_flow_audit_status = " + 
					ModelProjectProcess.EProjectDependFlowAuditState.PASS.getValue() + ")"));
			}
			
			if (UtilString.isNotEmpty(domain.getCondYearMatch()))
			{
				criteria.add(Restrictions.like("projectNo", domain.getCondYearMatch(), MatchMode.START));
			}
			
			// 条件查询
			VoProjectCond condVO = domain.getCondVO();
			if (condVO != null)
			{
				if (condVO.isValid())
				{
					String projectProgress = condVO.getCondProjectProcess();
					String projectStatus = condVO.getCondProjectStatus();
					
					if (UtilString.isNotEmpty(projectProgress))
					{
						// 项目进展
						if (projectProgress.equals("-1"))
						{
							// 待分配
							criteria.add(Restrictions.isNull("currentProcess"));
							criteria.add(Restrictions.eq("projectStatus", 
								ModelProject.EProjectStatus.APPROVING.getValue()));
						}
						else if (projectProgress.equals("-10"))
						{
							// 审批结束
							criteria.add(Restrictions.isNull("currentProcess"));
							criteria.add(Restrictions.in("projectStatus", 
								new Object[] {
									Integer.valueOf(ModelProject.EProjectStatus.APPROVED.getValue()),
									Integer.valueOf(ModelProject.EProjectStatus.REJECTED.getValue()),
									Integer.valueOf(ModelProject.EProjectStatus.SUSPENDED.getValue())
								}
							));
						}
						else
						{
							// 其他项目进展环节
							try
							{
								criteria.add(Restrictions.isNotNull("currentProcess"));
								criteria.createCriteria("currentProcess").add(
										Restrictions.eq("nodeTitle", new String(projectProgress.getBytes("ISO-8859-1"), "UTF-8")));
							}
							catch (Exception e)
							{
								// DO NOTHING HERE.
							}
						}
					}
					
					if (UtilString.isNotEmpty(projectStatus))
					{
						// 项目状态
						if (projectStatus.equals("-9"))
						{
							// 待分配
							criteria.add(Restrictions.isNull("currentProcess"));
							criteria.add(Restrictions.eq("projectStatus", 
								ModelProject.EProjectStatus.APPROVING.getValue()));
						}
						else if (projectStatus.equals("-10"))
						{
							// 审批结束
							criteria.add(Restrictions.isNull("currentProcess"));
							criteria.add(Restrictions.in("projectStatus", 
								new Object[] {
									Integer.valueOf(ModelProject.EProjectStatus.APPROVED.getValue()),
									Integer.valueOf(ModelProject.EProjectStatus.REJECTED.getValue())
								}
							));
						}
						else
						{
							// 其他状态
							criteria.add(Restrictions.isNotNull("currentProcess"));
							criteria.add(Restrictions.eq("projectStatus", Integer.valueOf(projectStatus)));
						}
					}
				}
				
				// 审批结果查询
				if (UtilString.isNotEmpty(condVO.getCondProjectAuditResult()))
				{
					if (Integer.valueOf(condVO.getCondProjectAuditResult()).equals(-9))
					{
						criteria.add(Restrictions.ne("projectStatus", 
								ModelProject.EProjectStatus.APPROVED.getValue()));
						criteria.add(Restrictions.ne("projectStatus", 
								ModelProject.EProjectStatus.REJECTED.getValue()));
					}
					else
					{
						criteria.add(Restrictions.eq("projectStatus", 
								Integer.valueOf(condVO.getCondProjectAuditResult())));
					}
				}
				
				// 年份查询
				if (UtilString.isNotEmpty(condVO.getCondProjectYear()))
				{
					if (UtilString.isNotEmpty(condVO.getCondProjectMonth()))
					{
						criteria.add(Restrictions.sqlRestriction(
								"p_createTime >= '" + (condVO.getCondProjectYear() + "-" + condVO.getCondProjectMonth() + "-01") + 
								"' and p_createTime <= '" + (condVO.getCondProjectYear() + "-" + condVO.getCondProjectMonth() + "-31") + "'"));
					}
					else
					{
						criteria.add(Restrictions.sqlRestriction(
							"p_createTime >= '" + (condVO.getCondProjectYear() + "-01-01") + "' and p_createTime <= '" + (condVO.getCondProjectYear() + "-12-31") + "'"));
					}
				}
				
				// 项目分配状态
				if (UtilString.isNotEmpty(condVO.getCondProjectAssignmentStatus()))
				{
					// 未分配
					if (condVO.getCondProjectAssignmentStatus().equals("0"))
					{
						criteria.add(Restrictions.isNull("currentProcess"));
						criteria.add(Restrictions.eq("projectStatus", 
							ModelProject.EProjectStatus.APPROVING.getValue()));
					}
					else
					{
						criteria.add(
							Restrictions.sqlRestriction(
								"(" +
									"(p_currentProcess IS NULL and p_status in (" + 
									Integer.valueOf(ModelProject.EProjectStatus.APPROVED.getValue()) + "," +
									Integer.valueOf(ModelProject.EProjectStatus.REJECTED.getValue()) + ")) OR " +
									"(p_currentProcess IS NOT NULL)" +
								")"
							)
						); 
					}
				}
				
				// 项目登记起始时间
				if (UtilString.isNotEmpty(condVO.getCondProjectCreationStartTime()))
				{
					criteria.add(
						Restrictions.sqlRestriction(
							"p_createTime >= '" + condVO.getCondProjectCreationStartTime() + "'"
						)
					);
				}
				
				// 项目登记终止时间
				if (UtilString.isNotEmpty(condVO.getCondProjectCreationEndTime()))
				{
					criteria.add(
						Restrictions.sqlRestriction(
							"p_createTime <= '" + condVO.getCondProjectCreationEndTime()  + "'"
						)
					);
			}
				
			}
			
			criteria.addOrder(Order.desc("projectPostTime"));
		}
		
		return criteria;
	}
	
	public void setDaoProject(DAOProject daoProject)
	{
		this.daoProject = daoProject;
	}

	public DAOProject getDaoProject()
	{
		return daoProject;
	}

}
